﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CDB.Model.Colunas;
using CDB.Model.Tabelas;
using CDB.DataLayer.Colunas;
using CDB.DataLayer.Tabelas;

namespace CDB.BusinessLayer.Utilitarios
{
    internal class BLGeradorProcedure
    {
        #region Constântes
        private const string Insert = "%%NOMEINSERT%%";
        private const string Update = "%%NOMEUPDATE%%";
        private const string Delete = "%%NOMEDELETE%%";
        private const string Select = "%%NOMEOBTER%%";
        private const string Listagem = "%%NOMELISTAR%%";
        #endregion

        #region Propriedades
        private string StringConnection { get; set; }
        private string Provider { get; set; }
        private List<Coluna> gLstColuna { get; set; }
        #endregion

        #region Construtor
        public BLGeradorProcedure(string pstrConnection, string pstrProvider)
        {
            this.StringConnection = pstrConnection;
            this.Provider = pstrProvider;
        }
        #endregion

        #region Métodos

        #region Gerar Proc Inserir
        ///-----------------------------------------------------
        /// <summary>
        /// Gera stored procedure Inserir
        /// </summary>
        /// <param name="pstrNomeTabela">Nome da Tabela</param>
        /// <returns>Stored Procedure Insert</returns>
        /// ----------------------------------------------------
        public string GerarProcInserir(string pstrNomeTabela)
        {
            int Count;
            StringBuilder strProc = new StringBuilder();
            DLColuna objDLColuna = new DLColuna(this.StringConnection, this.Provider);
            List<Coluna> lstColunas = new List<Coluna>(objDLColuna.Listar(pstrNomeTabela));
            string strNomeProc = this.GerarNomeProc(TipoProc.Insert, pstrNomeTabela);

            strProc.AppendLine(this.GetDropProc(TipoProc.Insert));
            strProc.AppendLine(this.GetCabecalhoProc(TipoProc.Insert));


            strProc.AppendLine("CREATE PROCEDURE [dbo.][" + Insert + "]");
            if (lstColunas.Count > 0)
            {
                strProc.AppendLine("(");
                Count = 1;
                lstColunas.RemoveAll(p => p.PK == true);

                foreach (Coluna objColuna in lstColunas)
                {
                    if (objColuna.Tipo.ToUpper() == "DATETIME" || objColuna.Tipo.ToUpper() == "DATE")
                    {
                        strProc.Append("\t@" + objColuna.Nome + "\t" + objColuna.Tipo.ToUpper());
                    }
                    else
                    {
                        strProc.Append("\t@" + objColuna.Nome + "\t" + objColuna.Tipo.ToUpper() + "(" + objColuna.Tamanho.ToString() + ")");
                    }

                    if (Count < lstColunas.Count)
                    {
                        strProc.Append(",\n");
                    }
                    else
                    {
                        strProc.Append("\n");
                    }

                    Count++;

                }
                strProc.AppendLine(")");
            }

            strProc.AppendLine("AS");
            strProc.AppendLine("INSERT INTO " + pstrNomeTabela + "(");
            Count = 1;
            foreach (Coluna objColuna in lstColunas)
            {
                strProc.Append("\t" + objColuna.Nome);

                if (Count < lstColunas.Count)
                {
                    strProc.Append(",\n");
                }
                else
                {
                    strProc.Append("\n");
                }

                Count++;
            }
            strProc.AppendLine(")");
            strProc.AppendLine("VALUE(");
            Count = 1;
            foreach (Coluna objColuna in lstColunas)
            {
                strProc.Append("\t@" + objColuna.Nome);

                if (Count < lstColunas.Count)
                {
                    strProc.Append(",\n");
                }
                else
                {
                    strProc.Append("\n");
                }

                Count++;
            }
            strProc.AppendLine(")");

            strProc.Replace(Insert, strNomeProc);

            return strProc.ToString();
        }
        #endregion

        #region Gerar Proc Delete
        ///-----------------------------------------------------
        /// <summary>
        /// Gera stored procedure Excluir
        /// </summary>
        /// <param name="pstrNomeTabela">Nome da Tabela</param>
        /// <returns>Stored Procedure Delete</returns>
        /// ----------------------------------------------------
        public string GerarProcDelete(string pstrNomeTabela)
        {

            StringBuilder strProc = new StringBuilder();
            DLColuna objDLColuna = new DLColuna(this.StringConnection, this.Provider);
            List<Coluna> lstColunas;

            try
            {
                lstColunas = new List<Coluna>(objDLColuna.Listar(pstrNomeTabela));
            }
            finally
            {
                objDLColuna.Finalizar();
            }

            if (lstColunas.Exists(p => p.PK == true))
            {
                string strNomeProc = this.GerarNomeProc(TipoProc.Delete, pstrNomeTabela);

                Coluna objColuna = lstColunas.Find(p => p.PK == true);
                strProc.AppendLine(this.GetDropProc(TipoProc.Delete));
                strProc.AppendLine(this.GetCabecalhoProc(TipoProc.Delete));

                strProc.AppendLine("CREATE PROCEDURE [dbo.][" + Delete + "]");
                strProc.AppendLine("(");
                strProc.AppendLine("\t@" + objColuna.Nome + "\t" + objColuna.Tipo.ToUpper() + "(" + objColuna.Tamanho + ")");
                strProc.AppendLine(")");
                strProc.AppendLine("AS");
                strProc.AppendLine("DELETE " + pstrNomeTabela);
                strProc.AppendLine(" WHERE " + objColuna.Nome + " = @" + objColuna.Nome);

                strProc.Replace(Delete, strNomeProc);
            }

            return strProc.ToString();
        }
        #endregion

        #region Gerar Proc Update
        ///--------------------------------------------------------------------
        /// <summary>
        /// Gera Stored Procedure de Update
        /// </summary>
        /// <param name="pstrNomeTabela">Nome da Tabela</param>
        /// <returns>Stored Procedure Update</returns>
        /// ------------------------------------------------------------------
        public string GerarProcUpdate(string pstrNomeTabela)
        {
            StringBuilder strProc = new StringBuilder();
            DLColuna objDLColuna = new DLColuna(this.StringConnection, this.Provider);
            List<Coluna> lstColunas;
            try
            {
                lstColunas = new List<Coluna>(objDLColuna.Listar(pstrNomeTabela));
            }
            finally
            {
                objDLColuna.Finalizar();
            }


            int Count = 1;
            if (lstColunas.Exists(p => p.PK == true))
            {
                string strNomeProc = this.GerarNomeProc(TipoProc.Update, pstrNomeTabela);
                Coluna objColunaPK = lstColunas.Find(p => p.PK == true);

                strProc.AppendLine(this.GetDropProc(TipoProc.Update));
                strProc.AppendLine(this.GetCabecalhoProc(TipoProc.Update));

                strProc.AppendLine("CREATE PROCEDURE [dbo.][" + Update + "]");
                strProc.AppendLine("(");
                foreach (Coluna ItemobjColuna in lstColunas)
                {
                    if (ItemobjColuna.Tipo.ToUpper() == "DATETIME" || ItemobjColuna.Tipo.ToUpper() == "DATE")
                    {
                        strProc.Append("\t@" + ItemobjColuna.Nome + "\t" + ItemobjColuna.Tipo.ToUpper());
                    }
                    else
                    {
                        strProc.Append("\t@" + ItemobjColuna.Nome + "\t" + ItemobjColuna.Tipo.ToUpper() + "(" + ItemobjColuna.Tamanho.ToString() + ")");
                    }

                    if (Count < lstColunas.Count)
                    {
                        strProc.Append(",\n");
                    }
                    else
                    {
                        strProc.Append("\n");
                    }

                    Count++;

                }
                strProc.AppendLine(")");
                strProc.AppendLine("AS");
                strProc.AppendLine("UPDATE " + pstrNomeTabela + " SET ");
                foreach (Coluna objItemColuna in lstColunas)
                {
                    if (objItemColuna.PK)
                        continue;

                    strProc.Append("\t" + objItemColuna.Nome + " = @" + objItemColuna.Nome);

                    if (Count < lstColunas.Count)
                    {
                        strProc.Append(",\n");
                    }
                    else
                    {
                        strProc.Append("\n");
                    }

                    Count++;
                }
                strProc.AppendLine("WHERE " + objColunaPK.Nome + " = @" + objColunaPK.Nome);

                strProc.Replace(Update, strNomeProc);
            }

            return strProc.ToString();
        }
        #endregion

        #region Gerar Proc Select
        ///--------------------------------------------------------------------
        /// <summary>
        /// Gera Stored Procedure de Select
        /// </summary>
        /// <param name="pstrNomeTabela">Nome da Tabela</param>
        /// <returns>Stored Procedure Select</returns>
        /// ------------------------------------------------------------------
        public string GerarProcSelect(string pstrNomeTabela)
        {
            StringBuilder strProc = new StringBuilder();
            DLColuna objDLColuna = new DLColuna(this.StringConnection, this.Provider);
            List<Coluna> lstColunas;

            try
            {
                lstColunas = new List<Coluna>(objDLColuna.Listar(pstrNomeTabela));
            }
            finally
            {
                objDLColuna.Finalizar();
            }

            int Count = 1;
            if (lstColunas.Exists(p => p.PK == true))
            {
                string strNomeProc = this.GerarNomeProc(TipoProc.Select, pstrNomeTabela);
                Coluna objColunaPK = lstColunas.Find(p => p.PK == true);
                strProc.AppendLine(this.GetDropProc(TipoProc.Select));
                strProc.AppendLine(this.GetCabecalhoProc(TipoProc.Select));

                strProc.AppendLine("CREATE PROCEDURE [dbo.][%%NOMEOBTER%%]");
                strProc.AppendLine("(");
                strProc.Append("\t@" + objColunaPK + ",\n");
                foreach (Coluna ItemobjColuna in lstColunas)
                {
                    if (ItemobjColuna.Tipo.ToUpper() == "DATETIME" || ItemobjColuna.Tipo.ToUpper() == "DATE")
                    {
                        strProc.Append("\t@OUT_" + ItemobjColuna.Nome + "\t" + ItemobjColuna.Tipo.ToUpper());
                    }
                    else
                    {
                        strProc.Append("\t@OUT_" + ItemobjColuna.Nome + "\t" + ItemobjColuna.Tipo.ToUpper() + "(" + ItemobjColuna.Tamanho.ToString() + ")");
                    }

                    if (Count < lstColunas.Count)
                    {
                        strProc.Append(",\n");
                    }
                    else
                    {
                        strProc.Append("\n");
                    }

                    Count++;

                }
                strProc.AppendLine(")");
                strProc.AppendLine("AS");
                strProc.AppendLine("SELECT ");
                Count = 1;
                foreach (Coluna objColuna in lstColunas)
                {
                    strProc.Append("\t@OUT_" + objColuna.Nome + " = " + objColuna.Nome);

                    if (Count < lstColunas.Count)
                    {
                        strProc.Append(",\n");
                    }
                    else
                    {
                        strProc.Append("\n");
                    }

                    Count++;
                }
                strProc.AppendLine("FROM " + pstrNomeTabela);
                strProc.AppendLine("WHERE " + objColunaPK.Nome + " = @" + objColunaPK.Nome);

                strProc.Replace(Select, strNomeProc);
            }
            return strProc.ToString();
        }
        #endregion

        #region Gerar Proc Listar
        ///--------------------------------------------------------------------
        /// <summary>
        /// Gera Stored Procedure de Listar
        /// </summary>
        /// <param name="pstrNomeTabela">Nome da Tabela</param>
        /// <returns>Stored Procedure Listar</returns>
        /// ------------------------------------------------------------------
        public string GerarProcListar(string pstrNomeTabela)
        {

            StringBuilder strProc = new StringBuilder();
            DLColuna objDLColuna = new DLColuna(this.StringConnection, this.Provider);
            List<Coluna> lstColunas;

            try
            {
                lstColunas = new List<Coluna>(objDLColuna.Listar(pstrNomeTabela));
            }
            finally
            {
                objDLColuna.Finalizar();
            }

            string strNomeProc = this.GerarNomeProc(TipoProc.Listagem, pstrNomeTabela);
            strProc.AppendLine(this.GetDropProc(TipoProc.Listagem));
            strProc.AppendLine(this.GetCabecalhoProc(TipoProc.Listagem));

            strProc.AppendLine("CREATE PROCEDURE [dbo.][%%NOMELISTAR%%]");
            strProc.AppendLine("(");
            int Count = 1;
            foreach (Coluna ItemobjColuna in lstColunas)
            {
                if (ItemobjColuna.Tipo.ToUpper() == "DATETIME" || ItemobjColuna.Tipo.ToUpper() == "DATE")
                {
                    strProc.Append("\t@" + ItemobjColuna.Nome + "\t" + ItemobjColuna.Tipo.ToUpper() + " = NULL");
                }
                else
                {
                    strProc.Append("\t@" + ItemobjColuna.Nome + "\t" + ItemobjColuna.Tipo.ToUpper() + "(" + ItemobjColuna.Tamanho.ToString() + ") = NULL");
                }

                if (Count < lstColunas.Count)
                {
                    strProc.Append(",\n");
                }
                else
                {
                    strProc.Append("\n");
                }

                Count++;

            }
            strProc.AppendLine(")");
            strProc.AppendLine("AS");
            strProc.AppendLine("SELECT ");
            Count = 1;
            foreach (Coluna objColuna in lstColunas)
            {
                strProc.Append("\t" + objColuna.Nome);

                if (Count < lstColunas.Count)
                {
                    strProc.Append(",\n");
                }
                else
                {
                    strProc.Append("\n");
                }

                Count++;
            }
            strProc.AppendLine("FROM " + pstrNomeTabela);
            strProc.AppendLine("WHERE ");
            Count = 1;
            foreach (Coluna objColuna in lstColunas)
            {
                strProc.Append("\t(" + objColuna.Nome + " IS NULL OR ");

                if (objColuna.Tipo.ToUpper() == "VARCHAR")
                {
                    strProc.Append(objColuna.Nome + " LIKE '%'+@" + objColuna.Nome + "+'%'");
                }
                else
                {
                    strProc.Append(objColuna.Nome + " = @" + objColuna.Nome);
                }

                if (Count < lstColunas.Count)
                {
                    strProc.AppendLine("AND");
                }
                else
                {
                    strProc.Append("\n");
                }

                Count++;
            }

            strProc.Replace(Listagem, strNomeProc);
            return strProc.ToString();
        }
        #endregion

        #region Gerar Drop Proc
        ///---------------------------------------------------------------------------
        /// <summary>
        /// Cria um if para verificar se a proc já existe no BD, se existir da um Drop 
        /// </summary>
        ///<history>
        /// rsilveira Created 07/09/2011
        ///</history>
        ///---------------------------------------------------------------------------
        private string GetDropProc(TipoProc pTipoProc)
        {
            StringBuilder objStringBuilder = new StringBuilder();
            string NomeProc = string.Empty;
            switch (pTipoProc)
            {
                case TipoProc.Insert:
                    NomeProc = Insert;
                    break;
                case TipoProc.Update:
                    NomeProc = Update;
                    break;
                case TipoProc.Delete:
                    NomeProc = Delete;
                    break;
                case TipoProc.Select:
                    NomeProc = Select;
                    break;
                case TipoProc.Listagem:
                    NomeProc = Listagem;
                    break;
            }

            objStringBuilder.AppendLine("IF ((SELECT COUNT(1) ");
            objStringBuilder.AppendLine("       FROM SYSOBJECTS ");
            objStringBuilder.AppendLine("       WHERE SYSOBJECTS.name = '" + NomeProc + "'))");
            objStringBuilder.AppendLine("   BEGIN ");
            objStringBuilder.AppendLine("       DROP PROCEDURE " + NomeProc);
            objStringBuilder.AppendLine("   END");
            objStringBuilder.AppendLine("GO");

            return objStringBuilder.ToString();
        }
        #endregion

        #region Gerar Cabecalho Proc
        ///---------------------------------------------------------------------------
        /// <summary>
        /// Gera o cabeçalho para proc 
        /// </summary>
        ///<history>
        /// rsilveira Created 07/09/2011
        ///</history>
        ///---------------------------------------------------------------------------
        private string GetCabecalhoProc(TipoProc pTipoProc)
        {
            StringBuilder strCabecalho = new StringBuilder();
            string strDescricao = string.Empty;
            switch (pTipoProc)
            {
                case TipoProc.Insert:
                    strDescricao = "Insere um registro na base de dados";
                    break;
                case TipoProc.Update:
                    strDescricao = "Altera um registro na base de dados";
                    break;
                case TipoProc.Delete:
                    strDescricao = "Exclui um registro na base de dados";
                    break;
                case TipoProc.Select:
                    strDescricao = "Recupera um registro na base de dados";
                    break;
                case TipoProc.Listagem:
                    strDescricao = "Lista os registros da base de dados";
                    break;
            }
            strCabecalho.AppendLine("/*------------------------------------------------------------");
            strCabecalho.AppendLine("Descrição:" + strDescricao);
            strCabecalho.AppendLine("Data criação:" + DateTime.Now.ToShortDateString());
            strCabecalho.AppendLine("Responsável:");
            strCabecalho.AppendLine("Data alteração:");
            strCabecalho.AppendLine("Responsável alteração:");
            strCabecalho.AppendLine("------------------------------------------------------------- */");



            return strCabecalho.ToString();
        }
        #endregion

        #region Gerar Nome Proc
        private string GerarNomeProc(TipoProc pTipoProc, string pNomeTabela)
        {
            string strPrefixo = "USP_";
            string strNomeProc = string.Empty;
            string strDescricao = string.Empty;
            switch (pTipoProc)
            {
                case TipoProc.Insert:
                    strDescricao = "I_";
                    break;
                case TipoProc.Update:
                    strDescricao = "U_";
                    break;
                case TipoProc.Delete:
                    strDescricao = "D_";
                    break;
                case TipoProc.Select:
                    strDescricao = "S_";
                    break;
                case TipoProc.Listagem:
                    strDescricao = "L_";
                    break;
            }

            if (pNomeTabela.Split('_').Length == 1)
            {
                strNomeProc = strPrefixo + strDescricao + pNomeTabela;
            }
            else if (pNomeTabela.Split('_').Length == 2)
            {
                strNomeProc = strPrefixo + strDescricao + pNomeTabela.Replace("_", string.Empty);
            }
            else if (pNomeTabela.Split('_').Length > 2)
            {
                string[] strSplit = pNomeTabela.Split('_');

                if (strSplit[0].Length == 3 && strSplit[1].Length == 3)
                {
                    strNomeProc = strPrefixo + strSplit[0] + "_" + strDescricao;

                    for (int i = 2; i < strSplit.Length; i++)
                    {
                        strNomeProc += strSplit[i];
                    }
                }
                else
                {

                    strNomeProc = strPrefixo + strDescricao;
                    for (int i = 0; i < strSplit.Length; i++)
                    {
                        strNomeProc += strSplit[i];
                    }

                }
            }

            return strNomeProc;

        }
        #endregion

        #endregion

        #region Enums
        private enum TipoProc
        {
            Insert = 1,
            Update,
            Delete,
            Select,
            Listagem
        }
        #endregion

    }
}
